/* tqueue.h */

#ifndef __TQUEUE_H__
#define __TQUEUE_H__ 1

#include <time.h>
#include <pthread.h>

#include "list.h"

#define TIME_SEC_MSEC   1000
#define TIME_SEC_NSEC   1000000000
#define TIME_MSEC_NSEC  1000000

#define tsadd(a, b, result) \
do { \
    (result).tv_sec = (a).tv_sec + (b).tv_sec; \
    (result).tv_nsec = (a).tv_nsec + (b).tv_nsec; \
    if ((result).tv_nsec >= TIME_SEC_NSEC) { \
        ++(result).tv_sec; \
        (result).tv_nsec -= TIME_SEC_NSEC; \
    } \
} while (0)

#define tscmp(a, b, CMP) \
(((a).tv_sec == (b).tv_sec) ? \
   ((a).tv_nsec CMP (b).tv_nsec) : \
   ((a).tv_sec CMP (b).tv_sec))

#define tssetmsec(tv, msec) \
do { \
    (tv).tv_sec = (msec) / TIME_SEC_MSEC; \
    (tv).tv_nsec = ((msec) % TIME_SEC_MSEC) * TIME_MSEC_NSEC; \
} while (0)

#define tsset(tv, sec, nsec) \
do { \
    (tv).tv_sec = (sec); \
    (tv).tv_nsec = (nsec); \
} while (0)

#define tsclear(tv) ((tv).tv_sec = (tv).tv_nsec = 0)
#define tsisset(tv) ((tv).tv_sec || (tv).tv_nsec)

#define tq_data(ptr, type, member) \
	container_of(ptr, type, member)
		

struct tq_elem {
	struct list_head list;
	struct timespec expires; /* expire time for task */
	pthread_t thread; /* who queued this task */
	void (*task)(struct tq_elem *);	/* pointer to task */
};

int taskqueue_init(void);
void taskqueue_destroy(void);
int add_task_abs(const struct timespec *expires,
	 struct tq_elem *tqi, void (*task)(struct tq_elem *));

static inline int add_task(int msec, struct tq_elem *tqi,
	void(*task)(struct tq_elem *))
{
	struct timespec expires, expire_in;

	tssetmsec(expires, msec);
	clock_gettime(CLOCK_REALTIME, &expire_in);
	tsadd(expire_in, expires, expire_in);

	return add_task_abs(&expire_in, tqi, task);
}

#endif /* __TQUEUE_H__ */
